package com.ly.mp.dal.comm.mybatis;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.mybatis.spring.transaction.SpringManagedTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.ly.mp.dal.comm.jdbc.DynamicDataSource;
import com.ly.mp.dal.comm.jdbc.ReadWriteDataSourceDecision;

public class MpSpringManagedTransaction extends SpringManagedTransaction {
    private static final Logger LOGGER = LoggerFactory.getLogger(MpSpringManagedTransaction.class);
    private String transactionPolicy;
    private DataSource dataSource;
    private Connection connection;
    private boolean isConnectionTransactional;
    private boolean autoCommit;

    public MpSpringManagedTransaction(DataSource dataSource) {
        super(dataSource);
        this.dataSource = dataSource;
    }

    public MpSpringManagedTransaction(DataSource dataSource, String transactionPolicy) {
        this(dataSource);
        this.dataSource = dataSource;
        this.transactionPolicy = transactionPolicy;
    }

    @Override
    public Connection getConnection() throws SQLException {
        if ("jta".equals(this.transactionPolicy)) {
            DataSource axDs = ((DynamicDataSource) this.dataSource).getTargetDataSource();
            LOGGER.info("mybatis分布式事务获取当前数据源key:{}", ReadWriteDataSourceDecision.getDsKey());
            this.connection = DataSourceUtils.getConnection(axDs);
            this.autoCommit = this.connection.getAutoCommit();
            this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, axDs);
            return this.connection;
        } else {
            LOGGER.debug("mybatis不是分布式事务模式,获取当前数据源key:{}", ReadWriteDataSourceDecision.getDsKey());
            if (this.connection == null) {
                this.openConnection();
            }

            return this.connection;
        }
    }

    private void openConnection() throws SQLException {
        this.connection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.connection.getAutoCommit();
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("JDBC Connection [{}] will {} be managed by Spring", this.connection, this.isConnectionTransactional ? " " : " not ");
        }

    }

    @Override
    public void commit() throws SQLException {
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Committing JDBC Connection [{}]", this.connection);
            }

            this.connection.commit();
        }

    }

    @Override
    public void rollback() throws SQLException {
        if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Rolling back JDBC Connection [{}]", this.connection);
            }

            this.connection.rollback();
        }

    }

    @Override
    public void close() {
        DataSourceUtils.releaseConnection(this.connection, this.dataSource);
    }

    @Override
    public Integer getTimeout() {
        ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
        return holder != null && holder.hasTimeout() ? holder.getTimeToLiveInSeconds() : null;
    }
}